home *** CD-ROM | disk | FTP | other *** search
/ The CICA Windows Explosion! / The CICA Windows Explosion! - Disc 2.iso / winsock / ircii2-6.zip / SRC\IRCII-2.6\SOURCE\NEWIO.C < prev    next >
C/C++ Source or Header  |  1995-01-09  |  8KB  |  445 lines

  1. /*
  2.  * newio.c: This is some handy stuff to deal with file descriptors in a way
  3.  * much like stdio's FILE pointers 
  4.  *
  5.  * IMPORTANT NOTE:  If you use the routines here-in, you shouldn't switch to
  6.  * using normal reads() on the descriptors cause that will cause bad things
  7.  * to happen.  If using any of these routines, use them all 
  8.  *
  9.  * Written By Michael Sandrof
  10.  *
  11.  * Copyright(c) 1990 
  12.  *
  13.  * See the COPYRIGHT file, or do a HELP IRCII COPYRIGHT 
  14.  */
  15.  
  16. #ifndef lint
  17. static    char    rcsid[] = "@(#)$Id: newio.c,v 1.21 1994/07/03 09:41:00 mrg Stab $";
  18. #endif
  19.  
  20. #include "irc.h"
  21. #include "ircaux.h"
  22.  
  23. #ifdef ISC22
  24. # include <sys/bsdtypes.h>
  25. #endif /* ISC22 */
  26.  
  27. #ifdef ESIX
  28. # include <lan/net_types.h>
  29. #endif /* ESIX */
  30.  
  31. #include "irc_std.h"
  32.  
  33. #define IO_BUFFER_SIZE 512
  34.  
  35. #define    WAIT_NL ((unsigned) 0x0001)
  36.  
  37. #ifdef FDSETSIZE
  38. # define IO_ARRAYLEN FDSETSIZE
  39. #else
  40. # ifdef FD_SETSIZE
  41. #  define IO_ARRAYLEN FD_SETSIZE
  42. # else
  43. #  define IO_ARRAYLEN NFDBITS
  44. # endif
  45. #endif
  46.  
  47. typedef    struct    myio_struct
  48. {
  49.     char    buffer[IO_BUFFER_SIZE + 1];
  50.     unsigned int    read_pos,
  51.             write_pos;
  52.     unsigned    misc_flags;
  53. #if defined(ESIX) || defined(_Windows)
  54.     unsigned    flags;
  55. #endif /* ESIX */
  56. #ifdef _Windows
  57.     int        fd;
  58. #endif
  59. }           MyIO;
  60.  
  61. #define IO_SOCKET 1
  62.  
  63. static    struct    timeval    right_away = { 0L, 0L };
  64. static    MyIO    *io_rec[IO_ARRAYLEN];
  65.  
  66. #ifdef _Windows
  67. #define get_ior(x)    (*get_io_rec(x))
  68.  
  69. MyIO **get_io_rec(int fd)
  70. {
  71.     int    i;
  72.  
  73.     for (i = 0; i < IO_ARRAYLEN; i++)
  74.     {
  75.         if (io_rec[i] && io_rec[i]->fd == fd)
  76.             return &io_rec[i];
  77.     }
  78.     for (i = 0; i < IO_ARRAYLEN; i++)
  79.     {
  80.         if (!io_rec[i])
  81.             return &io_rec[i];
  82.     }
  83. }
  84.  
  85. #else
  86. #define    get_ior(x)    io_rec[x]
  87. #endif
  88.  
  89. static    struct    timeval    dgets_timer;
  90. static    struct    timeval    *timer;
  91.     int    dgets_errno = 0;
  92.  
  93. MyIO * new_io_rec(int fd)
  94. {
  95.     MyIO *rec;
  96.  
  97.     rec = (MyIO *) new_malloc(sizeof(MyIO));
  98.     rec->read_pos = 0;
  99.     rec->write_pos = 0;
  100.     rec->flags = 0;
  101. #ifdef _Windows
  102.     rec->fd = fd;
  103. #endif
  104.     return rec;
  105. }
  106.  
  107. #if defined(ESIX) || defined(_Windows)
  108. static    void    init_io();
  109.  
  110. /* Esix must know if it is a socket or not. */
  111. void    mark_socket(int des)
  112. {
  113.     MyIO **rec;
  114.  
  115.     init_io();
  116.     rec = & get_ior(des);
  117.     if (*rec == (MyIO *) 0)
  118.         *rec = new_io_rec(des);
  119.     (*rec)->flags |= IO_SOCKET;
  120. }
  121.  
  122. void    unmark_socket(int des)
  123. {
  124.     MyIO **rec;
  125.  
  126.     init_io();
  127.     rec = & get_ior(des);
  128.     if (*rec == (MyIO *) 0)
  129.         *rec = new_io_rec(des);
  130.     (*rec)->flags &= ~IO_SOCKET;
  131. }
  132. #endif /* ESIX || _Windows */
  133.  
  134. /*
  135.  * dgets_timeout: does what you'd expect.  Sets a timeout in seconds for
  136.  * dgets to read a line.  if second is -1, then make it a poll.
  137.  */
  138. extern    time_t
  139. dgets_timeout(sec)
  140.     int    sec;
  141. {
  142.     time_t    old_timeout = dgets_timer.tv_sec;
  143.  
  144.     if (sec)
  145.     {
  146.         dgets_timer.tv_sec = (sec == -1) ? 0 : sec;
  147.         dgets_timer.tv_usec = 0;
  148.         timer = &dgets_timer;
  149.     }
  150.     else
  151.         timer = (struct timeval *) 0;
  152.     return old_timeout;
  153. }
  154.  
  155. static    void    init_io()
  156. {
  157.     static    int    first = 1;
  158.  
  159.     if (first)
  160.     {
  161.         int    c;
  162.  
  163.         for (c = 0; c < IO_ARRAYLEN; c++)
  164.             io_rec[c] = (MyIO *) 0;
  165.         (void) dgets_timeout(-1);
  166.         first = 0;
  167.     }
  168. }
  169.  
  170. /*
  171.  * dgets: works much like fgets except on descriptor rather than file
  172.  * pointers.  Returns the number of character read in.  Returns 0 on EOF and
  173.  * -1 on a timeout (see dgets_timeout()) 
  174.  */
  175. int    dgets(str, len, des, specials)
  176. char    *str;
  177. int    len;
  178. int    des;
  179. char    *specials;
  180. {
  181.     char    *ptr, ch;
  182.     int    cnt = 0,
  183.         c;
  184.     fd_set    rd;
  185.     int    WantNewLine = 0;
  186.     int    BufferEmpty;
  187.     int    i,
  188.         j;
  189.     MyIO **rec;
  190.  
  191.     init_io();
  192.     rec = & get_ior(des);
  193.     if (*rec == (MyIO *) 0)
  194.         *rec = new_io_rec(des);
  195.     if (len < 0)
  196.     {
  197.         WantNewLine = 1;
  198.         len = (-len);
  199.         (*rec)->misc_flags |= WAIT_NL;
  200.     }
  201.     while (1)
  202.     {
  203.         if ((BufferEmpty = ((*rec)->read_pos ==
  204.                 (*rec)->write_pos)) || WantNewLine)
  205.         {
  206.             if(BufferEmpty)
  207.             {
  208.                 (*rec)->read_pos = 0;
  209.                 (*rec)->write_pos = 0;
  210.             }
  211.             FD_ZERO(&rd);
  212.             FD_SET(des, &rd);
  213.             switch (select(des + 1, &rd, 0, 0, timer))
  214.             {
  215.             case 0:
  216.                 str[cnt] = (char) 0;
  217.                 dgets_errno = 0;
  218.                 return (-1);
  219.             default:
  220. #if defined(ESIX) || defined(_Windows)
  221.                 if ((*rec)->flags & IO_SOCKET)
  222.                 {
  223. #ifdef _Windows
  224.                     WSASetLastError(0);
  225. #endif
  226.                     c = recv(des, (*rec)->buffer +
  227.                       (*rec)->write_pos,
  228.                       IO_BUFFER_SIZE-(*rec)->write_pos,
  229.                       0);
  230.                 }
  231.                 else
  232. #endif /* ESIX */
  233.                     c = read(des, (*rec)->buffer +
  234.                      (*rec)->write_pos,
  235.                      IO_BUFFER_SIZE-(*rec)->write_pos);
  236.                 if (c <= 0)
  237.                 {
  238. #ifdef _Windows
  239.                     if ((*rec)->flags & IO_SOCKET)
  240.                     {
  241.                         dgets_errno == WSAGetLastError();
  242.                         if (dgets_errno == WSAEWOULDBLOCK ||
  243.                             dgets_errno == WSAEINTR)
  244.                         {
  245.                             return -1;
  246.                         }
  247.                         return 0;
  248.                     }
  249.                     else
  250.                     {
  251.                         dgets_errno = errno;
  252.                         return 0;
  253.                     }
  254.                     
  255. #else
  256.                     dgets_errno = errno;
  257.                     return 0;
  258. #endif
  259.                 }
  260.                 if (WantNewLine && specials)
  261.                 {
  262.                     ptr = (*rec)->buffer;
  263.                     for (i = (*rec)->write_pos;
  264.                         i < (*rec)->write_pos+c;i++)
  265.     /* This section re-indented - phone, jan 1993 */
  266.             {
  267.                 if((ch = ptr[i]) == specials[0])
  268.                 {
  269.                     if (i > 0)
  270.                     {
  271.                         bcopy(ptr + i - 1, ptr + i + 1,
  272.                             (*rec)->write_pos +
  273.                             c - i - 1);
  274.                         i -= 2;
  275.                         c -= 2;
  276.                     }
  277.                     else
  278.                     {
  279.                         bcopy(ptr, ptr + 1,
  280.                             (*rec)->write_pos +
  281.                             c - 1);
  282.                         i--;
  283.                         c--;
  284.                     }
  285.                 }
  286.                 else if (ch == specials[2])
  287.                 {
  288.                     for (j = i - 1; j >= 0 &&
  289.                             isspace(ptr[j]); j--)
  290.                         ;
  291.                     for (;j >= 0 && !isspace(ptr[j]); j--)
  292.                         ;
  293.                     bcopy(ptr + j + 1, ptr + i + 1,
  294.                         (*rec)->write_pos + c - i - 1);
  295.                     c -= (i - j);
  296.                     i = j;
  297.                 }
  298.                 else if (ch == specials[1])
  299.                 {
  300.                     for (j = i - 1;
  301.                         j >= 0 && ptr[j] != '\n'; j--);
  302.                     bcopy(ptr + j + 1, ptr + i + 1,
  303.                         (*rec)->write_pos + c - i - 1);
  304.                     c -= (i-j);
  305.                     i = j;
  306.                 }
  307.             }
  308.                 }
  309.                 (*rec)->write_pos += c;
  310.                 break;
  311.             }
  312.         }
  313.         ptr = (*rec)->buffer;
  314.         if (WantNewLine)
  315.         {
  316.             for (cnt = (*rec)->write_pos; cnt > 0;cnt--,ptr++)
  317.             {
  318.                 if (*ptr == '\n' || cnt == len-1)
  319.                 {
  320.                     *ptr = '\0';
  321.                     (void) strcpy(str, (*rec)->buffer);
  322.                     (*rec)->write_pos=cnt-1;
  323.                     bcopy((*rec)->buffer, ptr, cnt);
  324.                     dgets_errno = 0;
  325.                     return 1;
  326.                 }
  327.             }
  328.             return -2;
  329.         }
  330.         while ((*rec)->read_pos < (*rec)->write_pos)
  331.         {
  332.             if (((str[cnt++] = ptr[((*rec)->read_pos)++])
  333.                 == '\n') || (cnt == len))
  334.             {
  335.                 dgets_errno = 0;
  336.                 str[cnt] = (char) 0;
  337.                 return (cnt);
  338.             }
  339.         }
  340.     }
  341. }
  342.  
  343. /*
  344.  * new_select: works just like select(), execpt I trimmed out the excess
  345.  * parameters I didn't need.  
  346.  */
  347. int    new_select(rd, wd, timeout)
  348. fd_set    *rd,
  349.     *wd;
  350. struct    timeval    *timeout;
  351. {
  352.     int    i,
  353.         set = 0;
  354.         fd_set new;
  355.     struct    timeval    *newtimeout,
  356.             thetimeout;
  357.  
  358.     if (timeout)
  359.     {
  360.         newtimeout = &thetimeout;
  361.         bcopy(timeout, newtimeout, sizeof(struct timeval));
  362.     }
  363.     else
  364.         newtimeout = NULL;
  365.     init_io();
  366.     FD_ZERO(&new);
  367.     for (i = 0; i < IO_ARRAYLEN; i++)
  368.     {
  369.         if (io_rec[i] && !(io_rec[i]->misc_flags&WAIT_NL))
  370.         {
  371.             if (io_rec[i]->read_pos < io_rec[i]->write_pos)
  372.             {
  373. #ifdef _Windows
  374.                 FD_SET(io_rec[i]->fd, &new);
  375. #else
  376.                 FD_SET(i, &new);
  377. #endif
  378.                 set = 1;
  379.             }
  380.         }
  381.     }
  382.     if (set)
  383.     {
  384.         set = 0;
  385.         if (!(select(IO_ARRAYLEN, rd, wd, NULL, &right_away) > 0))
  386.             FD_ZERO(rd);
  387.         for (i = 0; i < IO_ARRAYLEN; i++)
  388.         {
  389.             if ((FD_ISSET(i, rd)) || (FD_ISSET(i, &new)))
  390.             {
  391.                 set++;
  392.                 FD_SET(i, rd);
  393.             }
  394.             else
  395.                 FD_CLR(i, rd);
  396.         }
  397.         return (set);
  398.     }
  399.     return (select(IO_ARRAYLEN, rd, wd, NULL, newtimeout));
  400. }
  401.  
  402. /* new_close: works just like close */
  403. void    new_close(des)
  404. int    des;
  405. {
  406. #ifdef ESIX
  407.     if (get_ior(des)->flags & IO_SOCKET)
  408.         t_close(des);
  409. #endif /* ESIX */
  410. #ifdef _Windows
  411.     if (get_ior(des)->flags & IO_SOCKET)
  412.         closesocket(des);
  413.     #else
  414.         close(des)
  415. #endif
  416.     new_free(&(get_ior(des)));
  417. #ifndef _Windows
  418.     close(des);
  419. #endif
  420. }
  421.  
  422. /* set's socket options */
  423. extern    void
  424. set_socket_options(s)
  425.     int    s;
  426. {
  427. #if defined(ESIX) || defined(_Windows)
  428.     mark_socket(s);
  429. #else
  430. #ifndef NO_STRUCT_LINGER
  431.     struct linger    lin;
  432. #endif
  433.     int    opt = 1;
  434.     int    optlen = sizeof(opt);
  435.  
  436.     (void) setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &opt, optlen);
  437.     opt = 1;
  438.     (void) setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, &opt, optlen);
  439. #ifndef NO_STRUCT_LINGER
  440.     lin.l_onoff = lin.l_linger = 0;
  441.     (void) setsockopt(s, SOL_SOCKET, SO_LINGER, &lin, optlen);
  442. #endif /* NO_STRUCT_LINGER */
  443. #endif /* ESIX */
  444. }
  445.